/*
 * TCSS 422 Process Control Simulator
 * Group Money: Al McKenzie, Michael Pitts, Taylor Zielske
 */

/**
 * A Basic process that can have no to many IO devices.
 * @author Michael Pitts
 * @version Dec 8, 2011
 */
public class BasicProcess extends AbstractProcess {
	
	/** Base probability of requesting IO. */
	private static double IO_PROB = 0.1;
	
	/** The potential IODevices this process can call. */
	private final IODevice[] my_devices;
	
	/** The device this process is waiting on. */
	private IODevice my_waiting_on;
	
	/**
	 * Creates a BasicProcess that can have no IO to lots.
	 * @param the_name is the name of the new Process.
	 * @param the_limit is the number of iterations for this process.
	 * @param the_devices is an array of IODevices to use.  If null, no IO
	 * where the more devices listed the more likely this Process will require IO.
	 */
	public BasicProcess(final String the_name, final int the_limit,
			final IODevice[] the_devices) {
		super(the_name, the_limit);
		if (the_devices == null) {
			my_devices = new IODevice[0];
		} else {
			my_devices = the_devices;
		}
	}

	@Override public SysCall run() {
		SysCall call = super.run();
		if (my_waiting_on != null) {
			my_waiting_on.service(this);
			my_waiting_on = null;
		} else if (call != SysCall.DONE && my_devices.length > 0) {
			call = getIO();
		} else {
			Main.out().println(toString() + " cranking the CPU.");
		}
		return call;
	}
	
	/**
	 * Gets if IO is requested by this Processes.
	 * @return {@link SysCall#IO} if IO is done, {@link SysCall#NOTHING} otherwise.
	 */
	private SysCall getIO() {
		final SysCall call;
		if (Math.random() < my_devices.length * IO_PROB) {
			call = SysCall.IO;
			final int index = (int) Math.round(Math.random() * my_devices.length - 0.5);
			my_waiting_on = my_devices[index];
			my_waiting_on.requestService(this);
		} else {
			call = SysCall.NOTHING;
			Main.out().println(toString() + " cranking the CPU.");
		}
		return call;
	}

	@Override public IODevice getWaitingOn() {
		return my_waiting_on;
	}

}
